#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define Convert(addrptr) ((struct sockaddr*)addrptr)

namespace Net_Work
{
    const static int defaultsocketfd = -1;
    const int backlog = 5 ;

    enum{
        SocketError = 1,
        BindErrot,
        ListenError,
    };
    class Socket
    {
    public:
        Socket(){}
        virtual ~Socket(){}
        virtual void CreateSocketOrDie() = 0;
        virtual void BindSocketOrDie(uint16_t port) = 0;
        virtual void ListenSocketOrDie(int backlog) = 0;
        virtual Socket* AcceptConnection(std::string *peerip, uint16_t* peerport) = 0;
        virtual bool ConnectServer(std::string &serverip, uint16_t serverport) = 0;
        virtual int GetSockfd() = 0;
        virtual void SetSockfd(int sockfd) = 0;
        virtual void CloseSockfd() = 0;
        virtual bool Recv(std::string* buffer, int size) = 0;
        virtual void Send(std::string& send_str) = 0;
    public:
        void BuildListenSocketMethod(uint16_t port, int backlog){
            CreateSocketOrDie();
            BindSocketOrDie(port);
            ListenSocketOrDie(backlog);
        }
        bool BuildConnectSocketMethod(std::string& serverip, uint16_t serverport){
            CreateSocketOrDie();
            return ConnectServer(serverip, serverport);
        }
        void BuildNormalSocketMethod(){
            CreateSocketOrDie();
        }
    };

//多态
// TcpSocket 类通过 override 关键字明确表明它正在覆盖基类的虚函数。
// 确保你的 TcpSocket 类也包含了这些函数的实现，并且它们的签名与基类中的纯虚函数签名相匹配。
    class TcpSocket:public Socket
    {
    public:
        TcpSocket(int sockfd = defaultsocketfd):_sockfd(sockfd){}
        ~TcpSocket(){}
        void CreateSocketOrDie() override{
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if(_sockfd < 0){
                exit(SocketError);
            }
        }
        void BindSocketOrDie(uint16_t port) override{
            sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(port);
            local.sin_addr.s_addr = INADDR_ANY;
            int n = ::bind(_sockfd, (struct sockaddr*)&local, sizeof(local));
            if(n < 0){
                exit(BindErrot);
            }
        }
        void ListenSocketOrDie(int backlog) override{
            int n = ::listen(_sockfd, backlog);
            if(n < 0){
                exit(ListenError);
            }
        }
        Socket* AcceptConnection(std::string* peerip, uint16_t* peerport)override{
            sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int newsockfd = ::accept(_sockfd, Convert(&peer), &len);
            if(newsockfd < 0)return nullptr;
            *peerport = ntohs(peer.sin_port);
            *peerip = inet_ntoa(peer.sin_addr);
            Socket* s = new TcpSocket(newsockfd);
            return s;
        }
        bool ConnectServer(std::string& serverip, uint16_t serverport)override{
            sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_addr.s_addr = inet_addr(serverip.c_str());
            server.sin_family = AF_INET;
            server.sin_port = htons(serverport);
            int n = ::connect(_sockfd, Convert(&server), sizeof(server));
            if(n == 0){
                return true;
            }else return false;
        }
        int GetSockfd()override{
            return _sockfd;
        }
        void SetSockfd(int sockfd)override{
            _sockfd = sockfd;
        }
        void CloseSockfd()override{
            if(_sockfd > defaultsocketfd)
                ::close(_sockfd);
        }
        bool Recv(std::string* buffer, int size)override{
            char inbuffer[size];
            ssize_t n = ::recv(_sockfd, inbuffer, size - 1, 0);
            if(n > 0){
                inbuffer[n] = 0;
                *buffer += inbuffer;
                return true;
            }else if(n == 0)return false;
            else return false;
        }
        void Send(std::string& send_str)override{
            send(_sockfd, send_str.c_str(), send_str.size(), 0);
        }
    private:
        int _sockfd;
    };
}